package authorization;


import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.logging.FileHandler;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
import virtualHD.VirtualHDException;


import com.sun.xacml.PDP;
import com.sun.xacml.ctx.RequestCtx;
import com.sun.xacml.ctx.ResponseCtx;
import com.sun.xacml.ctx.Result;

import jaxb.folderConf.*;

/**
 * A folder's PEP. When a FolderMaster wants to make an operation on a certain folder asks to this class
 * for permissions. 
 * Resource manager go see if in its config.xml file there's a line for FolderMaster's user and if
 * he/she is allowed to do that operation. FolderMaster will never execute any operation on a folder
 * unless ResourceManager gives it the permission to do that!
 * ResourceManager also keeps a log, registering every operation made on its folder
 * @author pasquale
 *
 */
public class ResourceManager{

	public String CONFIG_ROOT = null;
	public static final String CONFIG_FILENAME = "/config/config.xml";
	
	public static final String LOG_FILENAME = "/logs/"+(new SimpleDateFormat("yyyy-MM-dd-")).format(
			new Date())+"log.txt";
	
	public ResourceManager(String userConfigRoot, String folderName,PDP pdp){
		this.CONFIG_ROOT = userConfigRoot;
		this.pdp = pdp;
		this.folderName = folderName;

		//"data base" initialization
		this.xmlPath = CONFIG_ROOT+folderName+CONFIG_FILENAME;
		configuration = Config.getFromFile(xmlPath);
		
		//logger initialization
		try {
			this.logPath = CONFIG_ROOT+folderName+LOG_FILENAME;
			//creation of a file handler with append mode and simple formatted output
			FileHandler fh = new FileHandler(logPath,true);
			fh.setFormatter(new SimpleFormatter());
			logger = Logger.getLogger(folderName+".logger");
			logger.addHandler(fh);
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}


	public Integer askForAuth(String user,String resource,String action){
		logger.info(user+" asks for a "+action+" operation on "+resource);
		
		Integer decision = null;
		//let's search for user so we can determine his/her role
		String role = getUserRole(user);

		if(role != null){ //user was found in the config file
			RequestCtx XACMLrequest;
			try {
				XACMLrequest = RequestBuilder.createXACMLRequest(
						resource,
						role,action);
				ResponseCtx XACMLresponse = pdp.evaluate(XACMLrequest);
				
				Set<Result> results = XACMLresponse.getResults();
				Iterator<Result> it = results.iterator();
				Result result = it.next();

				decision = result.getDecision();	
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
		if((decision == null) || (decision != Result.DECISION_PERMIT))
			logger.warning(user+"'s request was not granted due to folder policy!");

		return decision;
	}
	
	public void cleanLogFile(){
		try {
			PrintWriter p = new PrintWriter(logPath);
			p.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
	}

	public String getFolderName(){
		return folderName;
	}

	private String getUserRole(String user){
		String role = null;
		List<Folder> userList = configuration.getUser(); //users present in the configuration file for this folder
		int index = -1;
		int i = 0;
		while((index == -1) && (i<userList.size()))
			if(userList.get(i).getUserid().equals(user))
				index = i;
			else
				i++;

		if(index != -1)
			role = userList.get(i).getRole();

		return role;
	}
	
	public synchronized void changeRole(jaxb.messages.Folder f) throws VirtualHDException{
		if (f.getUserid().equals(folderName))
			throw new VirtualHDException("You can't change your own role");

		boolean found = false;
		List<Folder> users = configuration.getUser();
		for (int i=0; i<users.size(); i++){
			if (users.get(i).getUserid().equalsIgnoreCase(f.getUserid())){
					users.get(i).setRole(f.getRole());
					found = true;
			}
		}
		
		if (found==false){
			Folder f2 = new Folder();
			f2.setUserid(f.getUserid());
			f2.setRole(f.getRole());
			users.add(f2);
			logger.info("Added "+f.getUserid()+" with role "+f.getRole());
		}else
			logger.info(f.getUserid()+" role changed to "+f.getRole());
		
		Config newConfiguration=new Config(users);
		
		//"data base" updating
		this.xmlPath = CONFIG_ROOT+folderName+CONFIG_FILENAME;
		
		newConfiguration.saveToFile(xmlPath);
				
	}
	
	private String folderName;
	private String xmlPath;
	private String logPath;
	private Config configuration;

	private PDP pdp;
	
	private Logger logger;

}
